/*
** AtariSys.c
** Atari specific part of the disassembler.
*/

#include <windows.h>
#include <windowsx.h>
#include <memory.h>
#include <string.h>
#include <stdlib.h>
#include <io.h>
#include "..\compusys.h"

#define ATARI_FONT "Atari.FON"

HINSTANCE hDllInst;
char szDllPath[_MAX_PATH];
char szFontPath[_MAX_PATH];

/*
** allocate global memory
*/
static BYTE *MemoryAlloc(WORD wSize)
{
     return GlobalAllocPtr(GHND, (DWORD) wSize);
}

/*
** resize global memory
*/
static BYTE *MemoryRealloc(BYTE *lpBuf, WORD wSize)
{
     return GlobalReAllocPtr(lpBuf, (DWORD) wSize, GMEM_MOVEABLE);
}

/*
** free global memory
*/
static void MemoryFree(BYTE *lpBuf)
{
     GlobalFreePtr(lpBuf);
}

/*
** declare Atari font
*/
BOOL CALLBACK __export CompuInit(HINSTANCE hInst)
{
char *szSlash;

     /*
     ** Load font.
     */
     GetModuleFileName(hDllInst, szDllPath, sizeof(szDllPath));
     strcpy(szFontPath, szDllPath);
     if (szSlash = strrchr(szFontPath, '\\'))
          strcpy(szSlash + 1, ATARI_FONT);
     else strcpy(szFontPath, ATARI_FONT);
     if (! AddFontResource(szFontPath))
          return FALSE;

     /*
     ** if the font loaded successfully, notify other applications.
     */
     SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
     return TRUE;
}

/*
** remove Atari font.
*/
void CALLBACK __export CompuTerm(void)
{
     RemoveFontResource(szFontPath);
     SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
}

/*
** retruns the menu item available
*/
WORD CALLBACK __export CompuGetMenu(void)
{
     return MENU_ALL;
}

/*
** load a segment from a binary file
*/
BOOL CALLBACK __export CompuLoadSegment(int fd, SEGMENT *lpSeg, BOOL bReadType)
{
WORD wSize;

     /*
     ** get segment size.
     */
     wSize = lpSeg->wEnd - lpSeg->wBegin + 1;

     /*
     ** allocate memory for data and for byte type.
     */
     lpSeg->lpDump = MemoryAlloc(wSize);
     if (lpSeg->lpDump == NULL)
          return FALSE;
     lpSeg->lpType = MemoryAlloc(wSize);
     if (lpSeg->lpType == NULL)
          {
          MemoryFree(lpSeg->lpDump);
          lpSeg->lpDump = NULL;
          return FALSE;
          }

     /*
     ** read segment from file.
     */
     if ((WORD) read(fd, lpSeg->lpDump, wSize) != wSize)
          return FALSE;
     if (bReadType)
          if ((WORD) read(fd, lpSeg->lpType, wSize) != wSize)
               return FALSE;
     return TRUE;
}

/*
** send segment description to segment listbox.
*/
BOOL CALLBACK __export CompuUpdateSegment(HWND hSegmentList, SEGMENT *lpSeg)
{
char szBuf[80];
DWORD dwIndex;

     wsprintf(szBuf, "$%04X-$%04X:%u ($%04X)", lpSeg->wBegin, lpSeg->wEnd, lpSeg->wEnd - lpSeg->wBegin + 1, lpSeg->wEnd - lpSeg->wBegin + 1);
     dwIndex = SendMessage(hSegmentList, LB_ADDSTRING, 0, (LPARAM) (LPCSTR) szBuf);
     return (dwIndex != LB_ERR);
}

/*
** read an Atari binary file.
*/
BOOL CALLBACK __export CompuReadFile(HWND hSegmentList, int fd, SEGMENT *Segment, int nFirstSeg)
{
short iMagic;
DWORD dwFileLength;
WORD wBegin, wEnd;
WORD wSize;
int nSeg;
char szBuf[80];
DWORD dwIndex;

     /*
     ** Check that the file begins with 2 0xFF.
     */
     if (read(fd, &iMagic, sizeof(iMagic)) != sizeof(iMagic))
          return FALSE;
     if (iMagic != -1)
          return FALSE;
     dwFileLength = (DWORD) (filelength(fd) - sizeof(iMagic));

     /*
     ** read all segments
     */
     nSeg = nFirstSeg;
     while (dwFileLength)
          {

          /*
          ** read segment start and end address.
          */
          if (read(fd, &wBegin, sizeof(wBegin)) != sizeof(wBegin))
               return TRUE;
          if (nSeg && (wBegin == 0xFFFF))
               {
               if (read(fd, &wBegin, sizeof(wBegin)) != sizeof(wBegin))
                    return FALSE;
               dwFileLength -= 2;
               }
          if (read(fd, &wEnd, sizeof(wEnd)) != sizeof(wEnd))
               return FALSE;
          if (wEnd < wBegin)
               return FALSE;
          dwFileLength -= sizeof(wBegin) + sizeof(wEnd);

          /*
          ** check data size.
          */
          wSize = wEnd - wBegin + 1;
          if ((DWORD) wSize > dwFileLength)
               return FALSE;

          /*
          ** read segment data.
          */
          Segment[nSeg].wBegin = wBegin;
          Segment[nSeg].wEnd = wEnd;
          Segment[nSeg].bBinary = TRUE;
          CompuLoadSegment(fd, &Segment[nSeg], FALSE);
          dwFileLength -= (DWORD) wSize;

          /*
          ** add this segment to the segment list.
          */
          wsprintf(szBuf, "$%04X-$%04X:(%u) %04X", wBegin, wEnd, wSize, wSize);
          dwIndex = SendMessage(hSegmentList, LB_ADDSTRING, 0, (LPARAM) (LPCSTR) szBuf);
          if (dwIndex == LB_ERR)
               return FALSE;

          /*
          ** next segment.
          */
          nSeg++;
          if (nSeg >= MAX_SEGMENTS)
               return FALSE;
          }
     return TRUE;
}

/*
** Value of return.
*/
BYTE CALLBACK __export CompuGetReturn(void)
{
     return 0x9B;
}

/*
** DLL entry point
*/
BOOL CALLBACK LibMain(HINSTANCE hinst, UINT wDS, UINT cbHeap, DWORD unused)
{
     hDllInst = hinst;
     return TRUE;
}

/*
** DLL exit point
*/
int FAR PASCAL _WEP(int unused)
{
     return TRUE;
}
